package net.vsame.url2sql.helper;

import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import net.vsame.url2sql.render.Render;
import net.vsame.url2sql.url.impl.UrlConfig;
import net.vsame.url2sql.utils.JdbcUtils;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Url2Sql上下文
 * 可以取得数据库连接
 * 请求参数 请求路径
 * @author <a href="mailto:gaollg@sina.com">Gaollg</a>
 * @data 2013-5-6
 *
 */
public class Url2SqlContext {
	
	private static Log LOG = LogFactory.getLog(Url2SqlContext.class);
	private Connection conn;
	private HttpServletRequest request;
	private HttpServletResponse response;
	
	private String extensionName;//扩展名
	private String requestUrl;//请求路径
	
	private String[] restfulParams;//rest参数
	private Map<String, String[]> params;//参数
	private UrlConfig urlConfig;
	
	//返回数据载体
	private Map<String, Object> datas = new LinkedHashMap<String, Object>();
	
	private static ConnSource connSource;
	private HttpSession servletSession;
	private Map<String, Object> session;
	private Render render;
	
	public Url2SqlContext(){
		datas.put("code", 0);
		datas.put("msg", "success");
	}
	
	public Connection getConn() {
		//每次请请都在一个线程内，故无需synchronized
		if(conn == null){
			if(connSource == null){
				conn = JdbcUtils.getConnection();
			}else{
				conn = connSource.getConnection();
			}
			try {
				conn.setAutoCommit(false);
			} catch (SQLException e) {
			}
		}
		return conn;
	}
	public void setConn(Connection conn) {
		this.conn = conn;
	}
	public HttpServletRequest getRequest() {
		return request;
	}
	public HttpSession getServletSession() {
		return servletSession;
	}
	public Map<String, Object> getSession() {
		if(session == null){
			session = new HashMap<String, Object>();
			if(this.servletSession != null){
				//复制Session中的值
				@SuppressWarnings("rawtypes")
				Enumeration e = this.servletSession.getAttributeNames();
				while (e.hasMoreElements()) {
					String sessionName = (String) e.nextElement();
					session.put(sessionName, servletSession.getAttribute(sessionName));
				}
			}
		}
		return session;
	}
	public void setSession(Map<String, Object> session) {
		this.session = session;
	}
	@SuppressWarnings("unchecked")
	public <T> T getSessionValueToType(String key, Class<T> clazz){
		Object o = this.getSession().get(key);
		if(o == null){
			return null;
		}
		return (T) o;
	}
	@SuppressWarnings("unchecked")
	public void setRequest(HttpServletRequest request) {
		this.request = request;
		if(request != null){
			params = request.getParameterMap();
			this.servletSession = request.getSession();
		}
	}
	public HttpServletResponse getResponse() {
		return response;
	}
	public void setResponse(HttpServletResponse response) {
		this.response = response;
	}
	public String getExtensionName() {
		return extensionName;
	}
	public void setExtensionName(String extensionName) {
		this.extensionName = extensionName;
	}
	public String getRequestUrl() {
		return requestUrl;
	}
	public void setRequestUrl(String requestUrl) {
		this.requestUrl = requestUrl;
	}
	public Map<String, String[]> getParams() {
		return params;
	}
	public String[] getParams(Object key){
		return params.get(key+"");
	}
	public String getParam(Object key){
		String[] array = params.get(key+"");
		if(array == null){
			return null;
		}
		return array[0];
	}
	public void setParams(Map<String, String[]> params) {
		this.params = params;
	}
	public Render getRender() {
		return render;
	}
	public void setRender(Render render) {
		this.render = render;
	}

	/**
	 * 取得对应基本类型（包括数组）
	 * @param clazz
	 * @param key
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public <T> T getParamByType(Class<T> clazz, String key){
		if(!clazz.isArray()){
			return TypeConvertHelper.parseType(clazz, getParam(key));
		}
		String[] params = getParams(key);
		if(params==null || params.length==0){
			return null;
		}
		Class<?> componentType = clazz.getComponentType();
		
		Object[] a = (Object[]) Array.newInstance(componentType, params.length);
		for (int i = 0; i < params.length; i++) {
			a[i] = TypeConvertHelper.parseType(componentType, params[i]);
		}
		return (T) a;
	}
	
	public UrlConfig getUrlConfig() {
		return urlConfig;
	}
	public void setUrlConfig(UrlConfig urlConfig) {
		this.urlConfig = urlConfig;
	}
	
	/**
	 * 设置参数
	 * @param restfulParam
	 */
	public void setRestfulParam(String restfulParam) {
		if(restfulParam == null){
			return ;
		}
		@SuppressWarnings("unchecked")
		Map<String, String[]> paraMap = request.getParameterMap();
		String[] arrays = restfulParam.split("/|_");
		params = new HashMap<String, String[]>(paraMap.size()+arrays.length, 1);
		if(!"".equals(restfulParam)){
			for(int i=0; i<arrays.length; i++){
				String[] temp = new String[1];
				temp[0] = arrays[i];
				params.put(i + "", temp);
			}
		}
		params.putAll(paraMap);
		this.restfulParams = arrays;
	}
	public String[] getRestfulParams() {
		return this.restfulParams;
	}
	public String getRestfulParam(int i) {
		if(i<this.restfulParams.length){
			return this.restfulParams[i];
		}
		return null;
	}
	
	//=================================================
	public Map<String, Object> getDatas() {
		return datas;
	}
	
	/**
	 * 如果包含错误(即code!=0) 返回true
	 * @return
	 */
	public boolean hasError(){
		return !datas.get("code").equals(0);
	}

	/**
	 * 填充有用的数据
	 * @param key
	 * @param value
	 */
	public void putUsefulData(String key, Object value){
		datas.put(key, value);
	}
	
	/**
	 * 填充有用的数据
	 * @param key
	 * @param value
	 */
	public void put(String key, Object value){
		datas.put(key, value);
	}
	
	/**
	 * 填充错误
	 * @param code
	 * @param msg
	 * @param clean true表示清除原有数据
	 */
	public void putError(int code, String msg, boolean clean){
		if(clean){
			datas.clear();
		}
		datas.put("code", code);
		datas.put("msg", msg);
	}
	
	/**
	 * 填充错误
	 * @param code
	 * @param msg
	 * @param clean true表示清除原有数据
	 */
	public void putError(int code, String msg){
		putError(code, msg, true);
	}
	
	//==========================================基础============================================
	
	/**
	 * code=-1 : 设置服务器内部错误(500)
	 * @param e 异常
	 * @param errorMsg 异常消息,如果传递null 则为 500:e.getMessage()
	 */
	public void error(Exception e, String errorMsg){
		LOG.error("error:", e);
		if(errorMsg == null){
			errorMsg = "500:" + e.getMessage();
		}
		putError(-1, errorMsg);
	}
	
	/**
	 * 填充表单错误
	 * @param msg
	 * @param errors
	 */
	public void putFormError(String msg, Map<String, String> errors){
		if(msg == null){
			msg = "Form has " + errors.keySet().size() + "Errors";
		}
		putError(-2, msg);
		putUsefulData("errors", errors);
	}
	
	/**
	 * 设置表单错误信息<br/>
	 * code=-2 : 请求参数无效。错误消息里会给出具体哪个参数不合法以及原因。(通常是数据校验,如果是登录,可自行构建错Map传参)
	 * @param errors
	 */
	public void putFormError(Map<String, String> errors){
		putError(-2, null);
		putUsefulData("errors", errors);
	}
	
	/**
	 * 填充错误
	 * code=-3 : 无API访问权限。
	 */
	public void putNoPermission(){
		putError(-3, "No Permission!");
	}
	
	/**
	 * 填充错误
	 * code=-4 : 禁止IP访问
	 * @param msg
	 */
	public void putBanIP(String msg){
		if(msg==null){
			msg = "";
		}
		putError(-4, "Ban IP visit!" + msg);
	}
	
	/**
	 * 填充错误
	 * code=-5 : API不存在
	 * @param msg
	 */
	public void put404(){
		putError(-5, "Api not exist!");
	}
	
	/**
	 * 填充错误
	 * code=-6 : 访问频率超限
	 * @param msg
	 */
	public void putBusy(){
		putError(-6, "Access frequency transfinite!");
	}
	
	//==========================================业务============================================
	/**
	 * 填充错误
	 * code=1 : 用户未登录
	 * @param msg
	 */
	public void putNoLogin(){
		putError(1, "Please Login!");
	}
	
	private static String firstLetterToUpper(String string) {
		char[] buffer = string.toCharArray();
		buffer[0] = Character.toUpperCase(string.charAt(0));
		return new String(buffer);
	}

	/**
	 * 从session中取值
	 * @param str
	 * @return
	 */
	public Object getSessionVal(String str){
		String[] keys = str.split("\\.");
		Object o = this.getSession().get(keys[0]);
		for (int i = 1; i < keys.length; i++) {
			String now = keys[i];
			if(o instanceof Map){
				@SuppressWarnings("rawtypes")
				Map m = (Map) o;
				o = m.get(now);
			}else{
				Class<? extends Object> clazz = o.getClass();
				try {
					Method m = clazz.getMethod("get" + firstLetterToUpper(now));
					o = m.invoke(o);
				} catch (Exception e) {
					throw new RuntimeException(e);
				}
			}
		}
		return o;
	}
	
	/**
	 * 销毁上下文，比如数据库连接
	 */
	public void destroy(){
		//释放数据库连接
		if(this.conn != null){
			try {
				try{
					this.conn.commit();
				}finally{
					this.conn.close();
				}
			} catch (Exception e) {
			}finally{
			}
		}
		//复制session至servletSession中
		if(this.servletSession != null && this.session != null){
			//复制Session中的值
			@SuppressWarnings("rawtypes")
			Enumeration e = this.servletSession.getAttributeNames();
			while (e.hasMoreElements()) {
				String sessionName = (String) e.nextElement();
				Object o = session.get(sessionName);
				if(o != null){
					servletSession.setAttribute(sessionName, o);
					session.remove(sessionName);
				}else{
					servletSession.removeAttribute(sessionName);
				}
			}
			for (Map.Entry<String, Object> entry : session.entrySet()){
				servletSession.setAttribute(entry.getKey(), entry.getValue());
			}
		}
	}
	
	public static ConnSource getConnSource() {
		return connSource;
	}

	public static void setConnSource(ConnSource connSource) {
		Url2SqlContext.connSource = connSource;
	}

	public static interface ConnSource {
		public Connection getConnection();
	}

}
